#include "ipc/Ftok.h"
#include "ipc/Cola.h"
#include "tcp/tcp.h"
#include "ipc/Shm.h"
#include "log.h"
#include <stdlib.h>
#include <unistd.h>
#include <vector>

//TODO: Hacer mas TCP-friendly
int leer_linea(int socket, char *buffer, int longitud_maxima){

    char c=0;
    char anterior=0;
    int i=0;
    do{
	anterior=c;
	if(recibir(socket, &c, 1) < 1){
	    buffer[i]=0;
	    clog(ROJO, "leer_linea sale con '%s' pendiente\n",buffer);
	    return -1;
	}

	buffer[i]=c;
	i++;
    }while( !(c == '\n' && anterior == '\r' ) && i < longitud_maxima);
    buffer[i]=0;

    return i;
}

void extraerParametros(const char* buffer, size_t len, const char* comando, char* parametro){
    unsigned int i=0;
    size_t longitud_comando = strlen(comando);
    parametro[0]=0;

    if(buffer[i] == ':'){ //prefijo
	for(;i<len && buffer[i] != ' ';i++);
	i++; //salteo el espacio
    }

    if(i<len){
	if(strncmp(&buffer[i], comando, longitud_comando)==0){
	    i+=longitud_comando+1;//salteo el comando y el espacio
	    unsigned int j=i;
	    for(;j<len && buffer[j] != ' ';j++);
	    memcpy(parametro, &buffer[i], j-i);
	    parametro[j-i]=0;

	    clog(AMARILLO, "ENCONTRADO MENSAJE '%s': '%s'\n",comando, parametro);
	}
    }
}

//Inspecciona el mensaje y lomodifica en caso de ser necesario
//Si devuelve true, el mensaje se debe enviar normalmente y no es modificado.
//Si devuelve false, el mensaje se debe devolver por donde vino y es modificado
bool procesarMensaje(char* mensaje, size_t len, char* servers){

    char server_local[50];
    
    extraerParametros(mensaje, len, "PING", server_local);
    
    if(server_local[0] != 0){
	clog(CYAN, "PING interceptado\n");

	mensaje[0] = 0;

	unsigned int i=0;
	while(servers[i] != 0){
	    char server_origen[50];

	    unsigned int j=i;
	    
	    for(;servers[j]!=0 && servers[j] != ' ';j++);
	    memcpy(server_origen, &servers[i], j-i);
	    server_origen[j-i]=0;

	    i=j+1;

	    strcat(mensaje, ":");
	    strcat(mensaje, server_origen);
	    strcat(mensaje, " PONG ");
	    strcat(mensaje, server_local); //el ultimo :server_local es opcional segun el RFC
	    strcat(mensaje, "\r\n");
	}
	    return false;
    }
    
    return true;
}

int main(int argc, char* argv[]){

    if(argc < 3){
	log("%s <sock_fd> <id_conexion>\n", argv[0]);
	exit(-1);
    }

    int sockfd = atoi(argv[1]);
    if(sockfd <= 0){
	clog(ROJO,"Error, el socket no puede ser %d\n", sockfd);
	exit(-1);
    }

    int id_conexion = atoi(argv[2]);
    if(id_conexion <= 0){
	clog(ROJO,"Error, el id_conexion no puede ser %s\n", argv[2]);
	exit(-1);
    }
    std::string path;
    path = ftok_crear_archivo("DTN");
    if(path.size()==0){
	clog(ROJO,"Error, no se pudo obtener el path para FTOK.\n");
	exit(-1);
    }

    std::string pathServers;
    pathServers = ftok_crear_archivo("SERVERS");
    if(pathServers.size()==0){
	clog(ROJO, "Error, no se pudo obtener el path para FTOK (SERVERS).\n");
	exit(-1);
    }

    Cola cola(path.c_str(), 1);

    Shm servers(pathServers.c_str(), id_conexion);
    char* base_servers = (char*)servers.getBase();

    //Saco mensajes del socket y los mando por la cola
    char mensaje[520];
    size_t longitud_maxima=513;
    size_t leido=0;

    while((leido=leer_linea(sockfd, mensaje, longitud_maxima)) != -1){
	mensaje[leido] = 0;
	clog(VERDE, "Leido el mensaje: %s (%d bytes para enviar)\n", mensaje, leido);
	if(mensaje[0] == 0){
	    printf("puto:%s", mensaje+2);
	    memmove(mensaje,mensaje+2,leido-2);
	}
	
	/******************
         PROCESO EL MENSAJE
	******************/

	bool saliente = procesarMensaje(mensaje, leido, base_servers);
	
	if(saliente)
	    //Pongo el mensaje en la cola
	    cola.enviar(id_conexion, mensaje, leido);
	else
		//lo devuelvo (PONG)
	    enviar(sockfd, mensaje, strlen(mensaje));


	memset(&mensaje, 0 ,sizeof(mensaje));
    }

    clog(ROJO,"El emisor finaliza.\n");
    return 0;
}
